﻿using System;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Configuration;
using Common.Logging;
using Crawler.Data;
using Crawler.Reports;
using HtmlAgilityPack;

namespace Crawler.Stuff
{
    public class Parser
    {
        private DataDataContext dc;
        private ILog log;
        private ReportStore rs;

        private int lastPostion = int.Parse(WebConfigurationManager.AppSettings["LastPostion"]);


        public Parser(ReportStore reportStore)
        {
            rs = reportStore;
            log = LogManager.GetCurrentClassLogger();
            log.DebugFormat("parser constracted");
            dc = new DataDataContext();

        }

        public static HtmlDocument LoadHtml(string html)
        {
            var doc = new HtmlDocument();
            doc.LoadHtml(html);
            return doc;
        }

        public int AppsCount(HtmlDocument doc)
        {
            string text = doc.DocumentNode.InnerText;
            int count;
            int indexOfFirstSpace = text.IndexOf(' ');
            int indexOfSecondP = text.IndexOf("при", StringComparison.InvariantCultureIgnoreCase);
            string parseMe = text.Substring(indexOfFirstSpace, indexOfSecondP - indexOfFirstSpace).Replace(" ", "");
            if (int.TryParse(parseMe, out count)) return count;
            return 0;
        }

        public static string FromInputToPostData(string shtml)
        {
            var html = LoadHtml(shtml);
            var inputs = html.DocumentNode.SelectNodes("//input");
            if (inputs == null || inputs.Count == 0)
            {
                LogManager.GetCurrentClassLogger().ErrorFormat("Parsing erorr. Cant find input[@name='s'] in {0}", html);
                return "";
            }
            var builder = new StringBuilder();
            for (int i = 0; i < inputs.Count; i++)
            {
                builder.AppendFormat("{0}={1}", inputs[i].Attributes["Name"].Value, HttpUtility.UrlEncode(inputs[i].Attributes["Value"].Value));
                if (i != inputs.Count - 1)
                {
                    builder.Append("&");
                }
            }
            return builder.ToString();
        }

        /// <summary>
        /// include position
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="postion"></param>
        public void ParseAndStore(HtmlDocument doc, int postion)
        {
            ParseAndStore(doc, postion, true);
        }

        /// <summary>
        /// disable position
        /// </summary>
        /// <param name="doc"></param>
        public void ParseAndStore(HtmlDocument doc)
        {
            ParseAndStore(doc, -100, false);
        }

        private void ParseAndStore(HtmlDocument doc, int positon, bool includePosition)
        {
            var trs = doc.DocumentNode.SelectNodes("//div/table/tr");
            if (trs == null || trs.Count == 0) LogManager.GetCurrentClassLogger().ErrorFormat("No trs in section");
            for (int i = 0; i < (trs == null ? 0 : trs.Count); i++)
            {
                var appId = doc.DocumentNode.SelectSingleNode(
                  string.Format(
                      "//div[{0}]/table/tr/td[2]/div/dl/dd[1]/div/a",
                      i + 1
                      ));

                bool hasDescription = doc.DocumentNode.SelectNodes(string.Format(
                                                                         "//div[{0}]/table/tr/td[2]/div/dl/dd",
                                                                         i + 1
                                                                         )).Count == 4;
                bool isNewApp = false;
                var app = dc.Apps.FirstOrDefault(a => a.AppId == (appId == null ? "" : appId.Attributes["href"].Value));
                if (app == null)
                {
                    app = new App();
                    isNewApp = true;
                }


                var name = doc.DocumentNode.SelectSingleNode(
                    string.Format(
                        "//div[{0}]/table/tr/td[2]/div/dl/dd[1]/div/a",
                        i + 1
                        ));

                HtmlNode description = null;
                if (hasDescription)
                {
                    description = doc.DocumentNode.SelectSingleNode(
                        string.Format(
                            "//div[{0}]/table/tr/td[2]/div/dl/dd[2]/div",
                            i + 1
                            ));
                }

                var type = doc.DocumentNode.SelectSingleNode(
                    string.Format(
                        "//div[{0}]/table/tr/td[2]/div/dl/dd[{1}]/div",
                        i + 1, hasDescription ? 4 : 3
                        ));
                var imagePath = doc.DocumentNode.SelectSingleNode(
                    string.Format("//div[{0}]/table/tr/td[1]/a/div/img[1]",
                    i + 1));
                string developer = null;

                app.AppId = appId == null ? "" : appId.Attributes["href"].Value;
                app.Developer = developer == null ? "" : developer;
                app.ImagePath = imagePath == null ? "" : imagePath.Attributes["src"] == null ? "" : imagePath.Attributes["src"].Value;

                app.Name = name == null ? "" : name.InnerText;
                app.Description = description == null ? "" : description.InnerText;
                app.Type = type == null ? "" : type.InnerText;

                var users = doc.DocumentNode.SelectSingleNode(
                    string.Format(
                        "//div[{0}]/table/tr/td[2]/div/dl/dd[{1}]/div",
                        i + 1, hasDescription ? 3 : 2
                        ));


                var mUsers = users == null
                                 ? 0
                                 : Convert.ToInt32(
                                       users.InnerText.Remove(users.InnerText.IndexOf("у")).Replace
                                         (" ", ""));
                if (CanAddAppStat(app))
                {


                    var appStat = new AppStat
                                      {
                                          App = app,
                                          Users = mUsers,
                                          ParsingDate = DateTime.Now,
                                          Position = includePosition ? positon * 20 + i : lastPostion

                                      };
                    dc.AppStats.InsertOnSubmit(appStat);
                    log.Debug("Adding new appstat");
                    rs.Report.NewAppStats++;
                    rs.UpdateProperties();
                }

                if (isNewApp)
                {
                    dc.Apps.InsertOnSubmit(app);
                    log.Debug("Adding new app");
                    rs.Report.NewApps++;
                    rs.UpdateProperties();
                }

            }
            dc.SubmitChanges();
        }



        private bool CanAddAppStat(App app)
        {
            var lastStat = app.AppStats.OrderByDescending(s => s.ParsingDate).FirstOrDefault();
            bool canadd = lastStat == null ? true : lastStat.ParsingDate.Day != DateTime.Now.Day;
            if (!canadd)
            {
                log.DebugFormat("statt for appid {0} allready exists", app.Id);
            }
            return canadd;
        }
    }
}
